/*
 * @(#)AuditEventHandler.java
 * Date 2013-10-31
 * Version 1.0
 * Author Jim Horner
 * Copyright (c)2012
 */


package us.hornerscorners.lamppost.atna.receiver;

import com.nesscomputing.syslog4j.server.SyslogServerEventIF;
import com.nesscomputing.syslog4j.server.SyslogServerIF;
import com.nesscomputing.syslog4j.server.SyslogServerSessionlessEventHandlerIF;
import java.net.SocketAddress;

import org.apache.commons.lang3.StringUtils;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import us.hornerscorners.lamppost.atna.service.IAuditEventService;

import us.hornerscorners.lamppost.model.audit.AuditEvent;
import us.hornerscorners.lamppost.model.audit.AuditMessage;

import us.hornerscorners.lamppost.utils.MarshallUtils;


/**
 * Class description
 *
 *
 * @version        v1.0, 2013-10-31
 * @author         Jim Horner
 */
public class AuditEventHandler implements SyslogServerSessionlessEventHandlerIF {

    /** Field description */
    private final IAuditEventService auditMessageService;

    /** Field description */
    private final Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * Constructs ...
     *
     *
     * @param service
     */
    public AuditEventHandler(IAuditEventService service) {

        super();
        this.auditMessageService = service;
    }

    /**
     * Method description
     *
     *
     * @param ssif
     */
    @Override
    public void destroy(SyslogServerIF ssif) {

        logger.debug("Handler destroy.");
    }

    /**
     * Method description
     *
     *
     * @param syslogServer
     * @param socketAddress
     * @param event
     */
    @Override
    public void event(SyslogServerIF syslogServer, SocketAddress socketAddress,
                      SyslogServerEventIF event) {

        AuditEvent auditEvent = new AuditEvent();

        try {

            String raw = new String(event.getRaw());

            logger.debug("Received message [{}].", raw);

            // The XML message is after the 7 or 8 space
            String eventString = removeHeader(raw);

            logger.debug("Marshal message [{}].", eventString);

            AuditMessage auditMessage = MarshallUtils.unmarshall(eventString,
                                            AuditMessage.class);

            auditEvent.setMessage(auditMessage);
            auditEvent.setFacility(event.getFacility().name());
            auditEvent.setEventDateTime(new DateTime(event.getDate(), DateTimeZone.UTC));
            auditEvent.setHost(event.getHost());
            auditEvent.setLevel(event.getLevel().name());

            this.auditMessageService.recordAuditEvent(auditEvent);

        } catch (Exception e) {

            logger.error("Exception", e);
        }
    }

    /**
     * Method description
     *
     *
     * @param syslogServer
     * @param socketAddress
     * @param exception
     */
    @Override
    public void exception(SyslogServerIF syslogServer,
                          java.net.SocketAddress socketAddress,
                          java.lang.Exception exception) {

        logger.error("Handler exception.", exception);
    }

    /**
     * Method description
     *
     *
     * @param ssif
     */
    @Override
    public void initialize(SyslogServerIF ssif) {

        logger.debug("Handler initialize.");
    }

    /**
     * Method description
     *
     *
     * @param message
     *
     * @return
     */
    protected String removeHeader(String message) {

        String eventString = StringUtils.trimToEmpty(message);

        if (StringUtils.isBlank(eventString)) {
            throw new IllegalStateException("Message is blank.");
        }

        // if it starts with <pri> then 7 spaces
        // if it starts with num of bytes then 8 spaces (not tested well)
        int numOfSpaces = ((eventString.charAt(0) == '<') ? 7 : 8);
        int count = 0;

        while (count < numOfSpaces) {

            int index = eventString.indexOf(" ");

            if ((index < 0) || (index + 1 > eventString.length())) {
                throw new IllegalStateException("Message is missing header.");
            }

            ++count;
            eventString = eventString.substring(index + 1);
        }

        return eventString;
    }
}
